#ifdef RT_USE_OLD_CONN_WRAP

#include "RtBase.h"
#include "RtCnBase.h"

#if !defined (_NEW_PROTO_TP)

///////////////////////////////////////////
//class CRtCnConn
///////////////////////////////////////////
CRtCnConn::CRtCnConn(DWORD dwMaxSendBufLen) 
: m_SendBuf(dwMaxSendBufLen)
, m_continuousIdleTime(0)
, m_isDataReceived(FALSE)
, m_isDataSent(FALSE)
#ifdef PRINT_CONN_DETAIL_LOG
, m_recvNum(0)
#endif
{
	m_pmbLocData = NULL;	
	m_pmbRecData = NULL;			

	m_pConnReqPDU = NULL;

	m_dwSeq4ACK = 0;
	m_dwCnt4JudgeACK = 0;

// 	m_dwLastSendTick = 0;
// 	m_dwLastRecvTick = 0;

	m_bNormalDisconn = FALSE;
	m_bNoRoom = FALSE;

	m_bDisableKeepaliveFlagOrNot = FALSE;

	Reset4Recv();

	m_keepAliveInterval = INTERVAL2;	// Default interval
	m_dwMaxBuffLen = dwMaxSendBufLen;
/***********Jobs Add at 2008.06.03 for flow control************************/
	m_dwCurrentBW = 0;
	m_dwTotalSendinSec = 0;
/***********Jobs Add at 2008.06.03 end************************/

}

CRtCnConn::~CRtCnConn() 
{
	Reset();
}

void CRtCnConn::NeedKeepAlive(BOOL bNeedKeepAlive)
{
	m_bNeedKeepAlive = bNeedKeepAlive;
}

void CRtCnConn::Reset()
{
	m_dwSeq4ACK = 0;
	m_dwCnt4JudgeACK = 0;
// 	m_dwLastSendTick = 0;
// 	m_dwLastRecvTick = 0;

	m_continuousIdleTime = 0;
	m_isDataReceived = FALSE;
	m_isDataSent = FALSE;

	if(m_pmbRecData)
	{
		m_pmbRecData->DestroyChained();
		m_pmbRecData = NULL;
	}
	
	m_SendBuf.Reset();

	if(m_pmbLocData)
	{
		m_pmbLocData->DestroyChained();
		m_pmbLocData = NULL;
	}

	if(m_pConnReqPDU)
	{
		m_pConnReqPDU->DestroyChained();
		m_pConnReqPDU = NULL;
	}

	Reset4Recv();

	//Base class
	CConnBase::Reset();
}

void CRtCnConn::Reset4Recv()
{
	m_dwPDULen = CRtCnPduBase::GetFixLength(CS_PDU_TYPE_HEAD);//2 bytes = PDU head length		
	m_byType = 0;		
	m_dwDataLen = 0;	
}

RtResult CRtCnConn::SendData(CRtMessageBlock &aData, CRtTransportParameter *aPara)
{ 
	if(m_wStatus == STATUS_UNCONNECTED)
	{
		if(m_dwMaxBuffLen > 0)
		{
			RT_WARNING_TRACE_THIS("CRtCnConn::SendData, status is wrong");
		}
		return RT_ERROR_NOT_AVAILABLE;
	}
	
	//RT_ASSERTE_RETURN(aData.GetChainedLength() > 0, RT_OK);
	if(aData.GetChainedLength() == 0)
		return RT_OK;

	RtResult result = RT_OK;

	m_isDataSent = TRUE;
	
	if(m_dwMaxBuffLen == 0)
	{
		if(m_wStatus != STATUS_DATA_CAN_SEND)
		{
			return RT_ERROR_NOT_AVAILABLE;
		}

		if(m_pmbRecData)
		{
			result = m_pITransport->SendData(*m_pmbRecData);
		}
		if(RT_SUCCEEDED(result))
		{
			DWORD dwDataLen = aData.GetChainedLength();
			CRtMessageBlock *pDataTmp = aData.DuplicateChained();
			//Create a new Data PDU
			CRtCnPduData SendPDU (TRUE, 0, dwDataLen, CS_PDU_TYPE_DATA_NORMAL, pDataTmp);
			if(m_pmbRecData)
			{
				m_pmbRecData->DestroyChained();
				m_pmbRecData = NULL;
			}
			CRtMessageBlock mb(SendPDU.GetFixLength());
			SendPDU.Encode(mb);
			m_pmbRecData = mb.DuplicateChained();
			result = m_pITransport->SendData(*m_pmbRecData);
			if(RT_SUCCEEDED(result))
			{
				m_pmbRecData->DestroyChained();
				m_pmbRecData = NULL;
			}
// 			m_dwLastSendTick = GetTickCountEx();
			aData.AdvanceChainedReadPtr(dwDataLen);//Advance upper layer data read ptr
			if(aPara)
			{
				aPara->m_dwHaveSent = dwDataLen;
			}
			return RT_OK;
		}
		return result;
	}

	//Try to send
	RtResult sendret = SendDataFromSendBuf();
	
	//RtResult result = RT_OK;
	//Put aData & m_dwSeq4ACK in SendBuf, wait for send later
	/*BOOL bPDUNeedACK = FALSE;
	if(m_cType == CRtConnectionManager::CTYPE_PDU_RELIABLE)
		bPDUNeedACK = TRUE;*/
	
	DWORD dwHaveAdd = m_SendBuf.AddDataPDU(&aData, m_bPDUNeedACK/*bPDUNeedACK*/);
	if(dwHaveAdd == 0)//There are not enough rooms for the aData
	{
		//RT_INFO_TRACE_THIS("CRtCnConn::SendData(), not enough rooms for the aData, m_dwSeq4ACK ="<<m_dwSeq4ACK);
		m_bNoRoom = TRUE;
		result = RT_ERROR_PARTIAL_DATA;
	}
	/*else
	{
		RT_INFO_TRACE_THIS("CRtCnConn::SendData(), m_dwTotalSend="<<m_dwTotalSend<<", dwHaveAdd="<<dwHaveAdd<<", data len="<<aData.GetChainedLength());
	}*/
/*
	++m_dwAddCount;
	RT_INFO_TRACE_THIS("CCon::SendData add command to buff, index = " << m_dwAddCount);
*/
	if(aPara)
	{
		aPara->m_dwHaveSent = dwHaveAdd;
	}

	//Try to send
	if(RT_SUCCEEDED(sendret))
		SendDataFromSendBuf();

	return result;
}

RtResult CRtCnConn::SetOption(DWORD aCommand, LPVOID aArg) 
{
	long lKAInterval = 0;

	switch (aCommand) 
	{
	case CS_OPT_MAX_SENDBUF_LEN:
		m_dwMaxBuffLen = *static_cast<DWORD*>(aArg);
		RT_INFO_TRACE_THIS("CRtCnConn::SetOption set max buff len = " << m_dwMaxBuffLen);
		/*if(m_dwMaxBuffLen != 0 && m_byConnType == CS_CONN_TYPE_RLB)
			m_bPDUNeedACK = TRUE;
		else
		{
			m_bPDUNeedACK = FALSE;
		}*/
//		if(m_pSendBuf)
			m_SendBuf.SetMaxBufLen(*static_cast<DWORD*>(aArg));
		break;
	case CS_OPT_KEEPALIVE_INTERVAL:
		m_keepAliveInterval = (*static_cast<WORD*>(aArg));
		
		RT_INFO_TRACE_THIS("CRtCnConn::SetOption(), CS_OPT_KEEPALIVE_INTERVAL = " << 
			m_keepAliveInterval << " seconds" << 
			" m_wStatus=" << m_wStatus);
		lKAInterval = (long)m_keepAliveInterval;
		if (m_wStatus == STATUS_DATA_CAN_SEND) {
//			m_Timer.Cancel();
			m_Timer.Schedule(this, CRtTimeValue(lKAInterval, 0));
		}
		break;
	case CS_OPT_DISABLE_RCVDATA_FLAG:
		m_bDisableKeepaliveFlagOrNot = (*static_cast<BOOL *>(aArg));
		break;
/***********Jobs Add at 2008.06.03 for flow control************************/
	case CS_OPT_SET_BANDWIDTH:
		m_dwCurrentBW = (*static_cast<DWORD*>(aArg));
		if(m_dwCurrentBW != 0 && m_dwCurrentBW <1000 )
			m_dwCurrentBW = 1000;
		//if(m_dwCurrentBW == 0)
		//	SendDataFromSendBuf();
		RT_INFO_TRACE_THIS("CRtCnConn::SetOption, SET BANDWIDTH="<<m_dwCurrentBW);
		break;
/***********Jobs Add at 2008.06.03 end************************/
		
	default:
		if(m_pITransport)
			return m_pITransport->SetOption(aCommand, aArg);
		return RT_ERROR_NOT_AVAILABLE;
	}
	return RT_OK;
}

RtResult CRtCnConn::GetOption(DWORD aCommand, LPVOID aArg) 
{
	switch (aCommand) 
	{
	case CS_OPT_MAX_SENDBUF_LEN:
		*(static_cast<DWORD*>(aArg)) = m_SendBuf.GetMaxBufLen();
		return RT_OK;
	case CS_OPT_KEEPALIVE_INTERVAL:
		*(static_cast<WORD*>(aArg)) = m_keepAliveInterval;
		return RT_OK;
	case CS_OPT_DISABLE_RCVDATA_FLAG:
		(*static_cast<BOOL *>(aArg)) = m_bDisableKeepaliveFlagOrNot;
		return RT_OK;
	default:
		if(m_pITransport)
			return m_pITransport->GetOption(aCommand, aArg);
		return RT_ERROR_NOT_AVAILABLE;
	}
}

RtResult CRtCnConn::Disconnect(RtResult aReason) 
{
	//Leave it to child
	if(m_pmbRecData)
	{
		m_pmbRecData->DestroyChained();
		m_pmbRecData = NULL;
	}
	return RT_OK;
}

void CRtCnConn::OnSend(IRtTransport *aTrptId, CRtTransportParameter *aPara)
{
	RT_INFO_TRACE_THIS("CRtCnConn::OnSend, trpt="<<aTrptId);
	RT_ASSERTE(m_pITransport == aTrptId);

	if(m_wStatus != STATUS_DATA_CAN_SEND)
			return;//Cannot send data now

	//Get data from SendBuf & try to send it
	//Try to send
	if(m_dwMaxBuffLen != 0)
		SendDataFromSendBuf();
	else
	{
		if(m_pmbRecData)
		{
			RtResult result = m_pITransport->SendData(*m_pmbRecData);
			if(RT_SUCCEEDED(result))
			{
				m_pmbRecData->DestroyChained();
				m_pmbRecData = NULL;
			}
		}
		if(m_pITransportSink)
		{
			//RT_INFO_TRACE_THIS("CRtCnConn::OnSend, callback onsend");
			m_pITransportSink->OnSend(this, aPara);
		}
	}
	/*
	//Callback, Indicate upper layer can send data now
	if(m_pITransportSink && m_bNoRoom)
	{
		//RT_INFO_TRACE_THIS("TP layer OnSend()");
		m_bNoRoom = FALSE;
		m_pITransportSink->OnSend(this, aPara);
	}
	*/
}

RtResult CRtCnConn::SendKeepAlive() 
{
	//Send Keep alive with m_dwSeq4ACK
	if(m_wStatus != STATUS_DATA_CAN_SEND)
			return RT_ERROR_NOT_AVAILABLE;//Cannot send data now

	RtResult ret = RT_OK;
	if(m_dwMaxBuffLen == 0)
	{
		if(m_pmbRecData)
		{
			ret = m_pITransport->SendData(*m_pmbRecData);
		}
		if(RT_SUCCEEDED(ret))
		{
			if(m_pmbRecData)
			{
				m_pmbRecData->DestroyChained();
				m_pmbRecData = NULL;
			}
			else
			{
				CRtCnPduKeepAlive SendPDU(0, CS_PDU_TYPE_KEEPALIVE);
				CRtMessageBlock mb(SendPDU.GetFixLength());
				SendPDU.Encode(mb);
				m_pmbRecData = mb.DuplicateChained();
				ret = m_pITransport->SendData(*m_pmbRecData);
				if(RT_SUCCEEDED(ret))
				{
// 					m_dwLastSendTick = GetTickCountEx();
					m_pmbRecData->DestroyChained();
					m_pmbRecData = NULL;
				}
			}
		}
		return ret;
	}
	//Try to send
	SendDataFromSendBuf();
	
	/*ret = */
	m_SendBuf.AddKeepAlivePDU();

/*
	if(ret != 0)
	{
		++m_dwAddCount;
		RT_INFO_TRACE_THIS("CCon::Add keep alive to buff, index = " << m_dwAddCount);
	}
*/
	//Try to send
	SendDataFromSendBuf();

	return RT_OK;
}

RtResult CRtCnConn::SendConnReq()
{
	RtResult result = RT_ERROR_FAILURE;
	int nTryTimes = 3;//Try 3 times, then give up

	//Send Conn Request with m_dwSeq4ACK & m_wChannel
	if(m_pConnReqPDU == NULL || m_pConnReqPDU->GetChainedLength() == 0)
	{
		//RT_INFO_TRACE_THIS("CRtCnConn::SendConnReq(), m_pConnReqPDU == NULL, make one");
		CRtCnPduConnReqResp preq(
			m_dwSeq4ACK, 
			m_wChannel, 
			CS_PDU_TYPE_CONN_REQ, 
			m_byConnType);
		m_dwCnt4JudgeACK = m_dwSeq4ACK;
		CRtMessageBlock mb(preq.GetFixLength());
		preq.Encode(mb);
		m_pConnReqPDU = mb.DuplicateChained();//m_pConnReqPDU will be Destroyed by OnRecvConnResp
	}

	//Keep the Conn Request PDU in m_pConnReqPDU for re-sending if need
	while(RT_FAILED(result) && nTryTimes-- > 0)
	{
		CRtMessageBlock* pTmpMb = m_pConnReqPDU->DuplicateChained();
		result = m_pITransport->SendData(*pTmpMb);
		RT_ASSERTE(RT_SUCCEEDED(result));
		pTmpMb->DestroyChained();
	}

	return result;
}

RtResult CRtCnConn::SendConnResp()
{
	//RT_INFO_TRACE_THIS("CRtCnConn::SendConnResp(), m_dwSeq4ACK = " << m_dwSeq4ACK);

	RtResult result = RT_ERROR_FAILURE;
	int nTryTimes = 3;//Try 3 times, then give up

	//Send Conn Response with m_dwSeq4ACK & m_wChannel
	CRtCnPduConnReqResp presp(
		m_dwSeq4ACK, 
		m_wChannel, 
		CS_PDU_TYPE_CONN_RESP, 
		m_byConnType);
	m_dwCnt4JudgeACK = m_dwSeq4ACK;
	CRtMessageBlock mb(presp.GetFixLength());
	presp.Encode(mb);

	//Keep the Conn Request PDU in m_pConnReqPDU for re-sending if need
	while(RT_FAILED(result) && nTryTimes-- > 0)
	{
		result = m_pITransport->SendData(mb);
		RT_ASSERTE(RT_SUCCEEDED(result));
	}

	return result;
}

RtResult CRtCnConn::SendDisconn(RtResult aReason)
{
	RT_INFO_TRACE_THIS("CRtCnConn::SendDisconn(), m_wStatus = "<<m_wStatus);

	if(NULL==m_pITransport.Get())
		return RT_ERROR_NOT_AVAILABLE;
	//Send Keep alive with m_dwSeq4ACK
	/*if(m_wStatus != STATUS_DATA_CAN_SEND)
			return RT_ERROR_NOT_AVAILABLE;//Cannot send data now*/

	RtResult ret = RT_OK;
	if(m_dwMaxBuffLen == 0)
	{
		if(m_pmbRecData)
		{
			ret = m_pITransport->SendData(*m_pmbRecData);
		}
		if(RT_SUCCEEDED(ret))
		{
			CRtCnPduDisconn SendPDU(aReason, CS_PDU_TYPE_DISCONN);
			if(m_pmbRecData)
			{
				m_pmbRecData->DestroyChained();
				m_pmbRecData = NULL;
			}
			CRtMessageBlock mb(SendPDU.GetFixLength());
			SendPDU.Encode(mb);
			m_pmbRecData = mb.DuplicateChained();
			ret = m_pITransport->SendData(*m_pmbRecData);
			if(RT_OK == ret)
			{
				m_pmbRecData->DestroyChained();
				m_pmbRecData = NULL;
			}
		}
		return ret;
	}
	
	//Try to send
	ret = SendDataFromSendBuf();
	if (ret==RT_ERROR_PARTIAL_DATA)
		return ret;
	
	CRtCnPduDisconn disconnPdu(aReason, CS_PDU_TYPE_DISCONN);
	CRtMessageBlock mb(disconnPdu.GetFixLength());
	disconnPdu.Encode(mb);
	return m_pITransport->SendData(mb);

// 	m_SendBuf.AddDisconnPDU(aReason);
// 	SendDataFromSendBuf();
// 	return RT_OK;
}

void CRtCnConn::DoACK(DWORD dwACK)
{
//	RT_ASSERTE_RETURN_VOID(m_pSendBuf);
	m_SendBuf.DoACK(dwACK);//Really did ACK
	
	if(m_pITransportSink && m_bNoRoom)
	{
		m_bNoRoom = FALSE;
		if(RT_BIT_DISABLED(m_cBaseType, CRtConnectionManager::CTYPE_UDP))//If TCP
		{
			//RT_INFO_TRACE_THIS("CRtCnConn::DoACK, CALLBACK ONSEND");
			m_pITransportSink->OnSend(this);
		}
	}
}

RtResult CRtCnConn::SendDataFromSendBuf() 
{
/*
	if(!m_pITransport)
		return RT_ERROR_FAILURE;
	RT_ASSERTE(m_dwMaxBuffLen > 0);
*/
	if (m_wStatus!=STATUS_DATA_CAN_SEND)
		return RT_ERROR_WRONG_STATUS;
	
	DWORD dwCanSend = 0x1FFFFFFF;

	if(m_dwCurrentBW > 0)
	{
		if(m_dwTotalSendinSec >= m_dwCurrentBW)
		{
			//RT_INFO_TRACE_THIS("CRtCnConn::SendDataFromSendBuf, m_dwTotalSendinSec="<<m_dwTotalSendinSec<<", m_dwCurrentBW="<<m_dwCurrentBW);
			return RT_ERROR_PARTIAL_DATA;
		}
		else
			dwCanSend = m_dwCurrentBW - m_dwTotalSendinSec;
	}
	RtResult result = RT_OK;
	//Try to send data from SendBuf
	CRtMessageBlock *pmb;
	DWORD dwSendACK;
	m_SendBuf.GetData(pmb,dwSendACK);
	DWORD dwLen;
	DWORD dwSended;
	while(pmb && dwCanSend > 0 /* && pmb->GetChainedLength() > 0 && RT_SUCCEEDED(result)*/)//Data can send
	{
		dwLen = pmb->GetChainedLength();
		RT_ASSERTE(dwLen > 0);
		if(dwLen <= dwCanSend + 128)
		{
			result = m_pITransport->SendData(*pmb);
		}
		else
		{
			CRtTransportParameter aParam;
			aParam.m_dwHaveSent = dwCanSend;
			m_pITransport->SendData(*pmb, &aParam);
			result = RT_ERROR_PARTIAL_DATA;//ONLY SEND A PART DATA, SO IT SHOULD RETURN PARTIAL DATA 
		}
		//DWORD dwLenBeforeSend, dwLenAfterSend = 0;
		//dwLenBeforeSend = pmb->GetChainedLength();
		//dwLenAfterSend = pmb->GetChainedLength();
//		RT_INFO_TRACE_THIS("CRtCnConn::SendDataFromSendBuf send command result = " << result << " max buff = " << m_dwMaxBuffLen);
		dwSended = dwLen - pmb->GetChainedLength();
		m_dwTotalSendinSec += dwSended;
		if(dwCanSend > dwSended)
			dwCanSend -= dwSended;
		else
			dwCanSend = 0;

		if(RT_FAILED(result))
		{
			return result;
		}
/*
		++m_dwSuccCount;
		RT_INFO_TRACE_THIS("::SendDataFromBuff, send command, index = " << m_dwSuccCount);
*/
// 		m_dwLastSendTick = GetTickCountEx();
		m_SendBuf.DataSentLen(/*dwLenBeforeSend - dwLenAfterSend*/0);
		
		/*
		 *	it is wrong, may get wrong pdu if data send partly.
		 */
		m_dwCnt4JudgeACK = dwSendACK;
		m_SendBuf.GetData(pmb,dwSendACK);

	}
	return (pmb!=NULL) ? RT_ERROR_PARTIAL_DATA : RT_OK;
}

void CRtCnConn::OnRecvConnResp()
{
	//Empty, leave it to child
	return;
}

void CRtCnConn::OnRecvConnReq()
{
	//Empty, leave it to child
	return;
}

//Server using
void CRtCnConn::OnRecvDisconn()
{
	//Get reason from Disconn PDU
	CRtCnPduDisconn pdc;
	CRtMessageBlock mb(pdc.GetFixLength());
	pdc.Decode(*m_pmbLocData);

	WORD wReason = pdc.GetReason();
	RT_INFO_TRACE_THIS("CRtCnConn::OnRecvDisconn(), Normal disconnect, wReason = " << wReason);

	RtResult aReason = (RtResult)wReason;
	
	//Waiting for peer do Disconnection
	m_bNormalDisconn = TRUE;

	m_Timer.Cancel();
	
#if 0
	SetCurrStatus(STATUS_UNCONNECTED);

	//Get Transport type
	DWORD dwTransType = CRtConnectionManager::CTYPE_NONE;

	if(m_pITransport)
		m_pITransport->GetOption(RT_OPT_TRANSPORT_TRAN_TYPE, (LPVOID)&dwTransType);
	
	//UDP will not get OnDisconnect(...) callback, so OnDisconnect to upper layer now
	if(RT_BIT_ENABLED(dwTransType, CRtConnectionManager::CTYPE_UDP))
	{
		if(m_pITransportSink)
			m_pITransportSink->OnDisconnect(aReason, this);//Network error, Callback to Upper layer
		
		//Waiting for a short time to be Removed
		m_disconn_timestamp = 
			CRtTimeValue::GetTimeOfDay() - CRtTimeValue(SERVER_NORMAL_DISCONN_TIMEOUT, 0);
	}

	//TCP will get OnDisconnect(..) callback later
#else

	OnDisconnect(aReason, m_pITransport.ParaIn());
#endif
}

void CRtCnConn::OnRecvKeepAlive()
{
	//Only for Reliable Conneciton
	if(m_cType == CRtConnectionManager::CTYPE_PDU_RELIABLE)
	{
#ifdef _DEBUG_DUMP_
		/////////////////////Test/////////////////////////////
		CRtMessageBlock *pTest = m_pmbLocData->DuplicateChained();
		CRtByteStreamIntel ss(*pTest);
		/////////////////////Test/////////////////////////////
#endif		
		
		//Get ACK from PDU
		CRtCnPduKeepAlive pka;
		pka.Decode(*m_pmbLocData);

#ifdef _DEBUG_DUMP_		
		/////////////////////Test/////////////////////////////
		::printf("OnRecvKeepAlive : ACK = %lu\n", pka.GetACK());
		char ch = '\0';
		int n = 6;
		while(n-- > 0)
		{
			ss >> ch;                            
			::printf("%02X ", ch);
		}
		::printf("\n");
		pTest->DestroyChained();
		/////////////////////Test/////////////////////////////
#endif		
		//RT_INFO_TRACE_THIS("CRtCnConn::OnRecvKeepAlive(), ACK = " << pka.GetACK());
		if(m_bPDUNeedACK && m_dwMaxBuffLen != 0)
			DoACK(pka.GetACK());
	}
	else	//Not Reliable Connection Case
	{
		//Only Advance KeepAlive PDU length, no ACK function
		m_pmbLocData->AdvanceChainedReadPtr(
			CRtCnPduBase::GetFixLength(CS_PDU_TYPE_KEEPALIVE));
	}
	
}

int CRtCnConn::GetPDUType()
{
	m_pmbLocData->Read(&m_byType, 1, NULL, FALSE);
	RT_ASSERTE(m_dwPDULen ==  CRtCnPduBase::GetFixLength(CS_PDU_TYPE_HEAD) || m_dwPDULen == 0 );
	m_dwPDULen = CRtCnPduBase::GetFixLength(m_byType, m_bPDUNeedACK);

	if(m_dwPDULen == 0 || m_byType == 0)	
	{
		RT_WARNING_TRACE_THIS("CRtCnConn::GetPDUType, wrong pdu! type="<<m_byType<<" len="<<m_dwPDULen);
		return -1;
	}

	return 0;
}

void CRtCnConn::OnReceive(CRtMessageBlock &aData, IRtTransport *aTrptId, CRtTransportParameter *aPara)
{
	//m_dwTotalRecv += aData.GetChainedLength();
	//RT_INFO_TRACE_THIS("CRtCnConn::OnReceive, get data length="<<aData.GetChainedLength()<<", m_dwTotalRecv="<<m_dwTotalRecv);
/*
//	RT_ASSERTE(m_pITransport == aTrptId);
	if (m_pITransport != aTrptId) {
		CRtInetAddr addrLocal1, addrPeer1;
		CRtInetAddr addrLocal2, addrPeer2;
		if (m_pITransport) {
			m_pITransport->GetOption(RT_OPT_TRANSPORT_LOCAL_ADDR, &addrLocal1);
			m_pITransport->GetOption(RT_OPT_TRANSPORT_PEER_ADDR, &addrPeer1);
		}
		if (aTrptId) {
			aTrptId->GetOption(RT_OPT_TRANSPORT_LOCAL_ADDR, &addrLocal2);
			aTrptId->GetOption(RT_OPT_TRANSPORT_PEER_ADDR, &addrPeer2);
		}
		RT_ERROR_TRACE_THIS("CRtCnConn::OnReceive,"
			" src_ip1=" << addrLocal1.GetIpDisplayName() << 
			" src_port1" << addrLocal1.GetPort() << 
			" dst_ip1=" << addrPeer1.GetIpDisplayName() << 
			" dst_port1" << addrPeer1.GetPort() <<
			" src_ip2=" << addrLocal2.GetIpDisplayName() << 
			" src_port2" << addrLocal2.GetPort() << 
			" dst_ip2=" << addrPeer2.GetIpDisplayName() << 
			" dst_port2" << addrPeer2.GetPort());
		aData.DestroyChained();
		RT_ASSERTE_RETURN_VOID(FALSE);
	}
*/

// 	m_dwLastRecvTick = GetTickCountEx();
	m_isDataReceived = TRUE;

	if(m_pmbLocData)
		m_pmbLocData->Append(aData.DuplicateChained());
	else
		m_pmbLocData = aData.DuplicateChained();
	
	RtResult ret = RT_OK;	
	while(m_pmbLocData && m_pmbLocData->GetChainedLength() >= (m_dwDataLen == 0? m_dwPDULen:m_dwDataLen) )
	{
		if(m_byType == 0)//get from GetPduType;
		{
			if(GetPDUType() == -1)
			{
				if(m_pITransport.Get())
				{
					CRtInetAddr addrPeer3;
					m_pITransport->GetOption(RT_OPT_TRANSPORT_PEER_ADDR, &addrPeer3);
					RT_ERROR_TRACE_THIS("CRtCnConn::OnReceive, unknown type, m_byType="<<m_byType<<" status="<<m_wStatus<<" peer="<<addrPeer3.GetIpDisplayName());
				}
				else
				{
					RT_ERROR_TRACE_THIS("CRtCnConn::OnReceive, unknown type, m_byType="<<m_byType<<" status="<<m_wStatus);
				}
				OnDisconnect(RT_ERROR_NOT_AVAILABLE, m_pITransport.ParaIn());
				return;
			}
		}

		if (m_dwDataLen==0 && m_pmbLocData->GetChainedLength() < m_dwPDULen)
		{
			RT_INFO_TRACE_THIS("CRtCnConn::OnReceive, partial PDU header. len="<<m_pmbLocData->GetChainedLength()<<" pdulen="<<m_dwPDULen<<" pdutype="<<m_byType);
			return;
		}

		//RT_INFO_TRACE_THIS("CRtCnConn::OnReceive, pdu="<<m_byType<<", message length="<<m_pmbLocData->GetChainedLength()<<", m_dwDataLen="<<m_dwDataLen<<",m_dwPDULen="<<m_dwPDULen);
		switch(m_byType)
		{
		case CS_PDU_TYPE_DATA_START:
		case CS_PDU_TYPE_DATA_NORMAL:
		{
			if(m_wStatus != STATUS_DATA_CAN_SEND)
			{
				ret = RT_ERROR_WRONG_STATUS;
				break;
			}
			if(m_dwDataLen == 0)
			{
/*
				RT_ASSERTE(m_dwPDULen > 0);
				if (m_pmbLocData->GetChainedLength() < m_dwPDULen)
				{
					RT_INFO_TRACE_THIS("CRtCnConn::OnReceive, half PDU header."
						" half_len=" << m_pmbLocData->GetChainedLength() << 
						" m_dwPDULen=" << m_dwPDULen);
					break;	//Waiting for next data block's coming
				}
*/

				CRtCnPduData pd(m_bPDUNeedACK);
				/*CRtMessageBlock *pTmp = m_pmbLocData->DuplicateChained();
				pd.DecodeWithOutData(*pTmp);*/
				
				pd.DecodeWithOutData(*m_pmbLocData);
				m_dwDataLen = pd.GetDataLen();
				//RT_INFO_TRACE_THIS("m_dwPDULen="<<m_dwPDULen<<", m_dwDataLen="<<m_dwDataLen<<", buffer len="<<m_pmbLocData->GetChainedLength());
				//m_dwPDULen += m_dwDataLen;
				
				//pTmp->DestroyChained();
				if(m_bPDUNeedACK && m_dwMaxBuffLen != 0)
					DoACK(pd.GetACK());
			}
			
			//if(m_pmbLocData->GetChainedLength() >= m_dwPDULen)
			if(m_pmbLocData->GetChainedLength() >= m_dwDataLen)
			{
				//CRtCnPduData pd(m_bPDUNeedACK);
				//pd.DecodeWithOutData(*m_pmbLocData);
				//if(m_bPDUNeedACK && m_dwMaxBuffLen != 0)
				//	DoACK(pd.GetACK());
				if(m_pITransportSink)
				{
					CRtMessageBlock *pTmp = m_pmbLocData->Disjoint(m_dwDataLen);
					m_pITransportSink->OnReceive(
						*m_pmbLocData, 
						this, 
						aPara
						);
					m_pmbLocData->DestroyChained();
					m_pmbLocData = pTmp;
				}
				else
				{
					RT_WARNING_TRACE_THIS("CRtCnConn::OnReceive, can't get the sink,discard data, len ="<<m_dwDataLen);
					m_pmbLocData->AdvanceChainedReadPtr(m_dwDataLen);
				}
				
				(m_byType==CS_PDU_TYPE_DATA_START) ? m_dwSeq4ACK = (m_dwPDULen + m_dwDataLen) : m_dwSeq4ACK += (m_dwPDULen + m_dwDataLen);
#ifdef PRINT_CONN_DETAIL_LOG
				RT_INFO_TRACE_THIS("CRtCnConn::OnReceive, seq="<<m_dwSeq4ACK<<" recvNum="<<++m_recvNum<<" m_dwCnt4JudgeACK="<<m_dwCnt4JudgeACK);
#endif
				m_SendBuf.SetSeq4ACK(m_dwSeq4ACK);
				if(m_bPDUNeedACK && m_dwSeq4ACK - m_dwCnt4JudgeACK >= 4096)
					SendKeepAlive();
				//Calculate finish
				
				Reset4Recv();
			}
			break;	
		}
		
		case CS_PDU_TYPE_CONN_REQ:
		{
			if(GetInstanceType() == SERVER_INSTANCE && m_wStatus==STATUS_CONNECTED)
			{
				OnRecvConnReq();//Server do
				Reset4Recv();
			}
			else
				ret= RT_ERROR_UNEXPECTED;
			break;
		}
		case CS_PDU_TYPE_CONN_RESP:
		{
			if(GetInstanceType() == CLIENT_INSTANCE && m_wStatus==STATUS_CONNECTED)
			{
				OnRecvConnResp();//Client do
				Reset4Recv();
			}
			else
			{
				ret = RT_ERROR_UNEXPECTED;
			}
			break;
		}
		case CS_PDU_TYPE_DISCONN:
			OnRecvDisconn();
			Reset4Recv();
			return;

		case CS_PDU_TYPE_KEEPALIVE:
			OnRecvKeepAlive();
			Reset4Recv();
			break;

		case CS_PDU_TYPE_RTT:
		{
			CRtCnPduRtt rttPdu;
			rttPdu.Decode(*m_pmbLocData);
			OnRecvRtt(rttPdu.GetTimestamp());
			Reset4Recv();
			break;
		}

		default:
			ret= RT_ERROR_NOT_IMPLEMENTED;
			break;
		}
		if(RT_FAILED(ret))
		{
			CRtInetAddr addrPeer4;
			aTrptId->GetOption(RT_OPT_TRANSPORT_PEER_ADDR, &addrPeer4);
			RT_ERROR_TRACE_THIS("CRtCnConn::OnReceive, unexpected pdu!"
				" ret="<<ret<<
				" m_byType=" << m_byType << 
				" m_wStatus=" << m_wStatus << 
				" m_dwDataLen=" << m_dwDataLen<<
				" peer="<<addrPeer4.GetIpDisplayName());
			OnDisconnect(RT_ERROR_NOT_AVAILABLE, aTrptId);
			return;
		}
	}
	//Garbage Reclaim
	if(m_pmbLocData && m_pmbLocData->GetChainedLength() == 0)
	{
		//RT_ASSERTE(m_pmbLocData->GetChainedLength() == 0);
		//m_pmbLocData = m_pmbLocData->ReclaimGarbage();
		m_pmbLocData->DestroyChained();
		m_pmbLocData = NULL;
		//RT_INFO_TRACE_THIS("CRtCnConn::OnReceive, len = "<<m_pmbLocData->GetChainedLength());
		//RT_ASSERTE(m_pmbLocData == NULL);
	}
}
#endif

#endif // RT_USE_OLD_CONN_WRAP

